package com.ruoyi.common.utils;

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

public class NightSurveillanceConverter {

    // 默认路径配置
    private static final String DEFAULT_INPUT_PATH = "C:\\Users\\lenovo\\Desktop\\返修\\夜视评测集\\距离镜头太近";    // 默认输入目录
    private static final String DEFAULT_OUTPUT_PATH = "C:\\Users\\lenovo\\Desktop\\far1"; // 默认输出目录

    // 夜晚监控效果参数配置
    private static final double BRIGHTNESS = -0.45;    // 更暗的亮度（模拟夜晚）
    private static final double CONTRAST = 2.0;        // 更高的对比度（增强夜视效果）
    private static final int BITRATE = 1500000;        // 更高码率保证高清质量
    private static final int FRAME_RATE = 20;          // 稍高帧率（夜视模式常用）
    private static final double NOISE_INTENSITY = 0.1; // 更强的噪点（模拟夜间传感器噪声）
    private static final double BLUR_SIGMA = 0.2;      // 轻微模糊（模拟低光条件）

    // 用于生成随机夜晚时间的Random实例
    private static final Random random = new Random();

    public static void main(String[] args) {
        // 设置默认路径
        String inputPath = DEFAULT_INPUT_PATH;
        String outputPath = DEFAULT_OUTPUT_PATH;

        // 检查是否有命令行参数
        if (args.length >= 1) {
            inputPath = args[0];
        }
        if (args.length >= 2) {
            outputPath = args[1];
        }

        // 打印使用的路径
        System.out.println("Night Surveillance Video Converter");
        System.out.println("Using input directory: " + inputPath);
        System.out.println("Using output directory: " + outputPath);

        File inputDir = new File(inputPath);
        File outputDir = new File(outputPath);

        // 检查输入目录
        if (!inputDir.exists() || !inputDir.isDirectory()) {
            System.err.println("Error: Input directory does not exist or is not a directory");
            System.err.println("Path: " + inputDir.getAbsolutePath());
            return;
        }

        // 处理视频文件
        try {
            processAllVideoFiles(inputDir, outputDir);
        } catch (Exception e) {
            System.err.println("Error during video processing: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 递归处理输入目录中的所有视频文件（包含子文件夹）
     *
     * @param inputDir 输入根目录
     * @param outputDir 输出根目录
     */
    private static void processAllVideoFiles(File inputDir, File outputDir) throws Exception {
        System.out.println("\nStarting night surveillance conversion...");
        System.out.println("Input directory: " + inputDir.getAbsolutePath());
        System.out.println("Output directory: " + outputDir.getAbsolutePath());
        System.out.println("Night effect parameters:");
        System.out.printf("  Brightness: %.2f, Contrast: %.2f%n", BRIGHTNESS, CONTRAST);
        System.out.printf("  Frame rate: %d fps, Bitrate: %d bps%n", FRAME_RATE, BITRATE);
        System.out.printf("  Noise: %.2f, Blur: %.2f%n", NOISE_INTENSITY, BLUR_SIGMA);

        // 收集所有视频文件路径（包含子文件夹）
        List<Path> allVideoFiles = new ArrayList<>();
        Files.walkFileTree(inputDir.toPath(), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                if (isVideoFile(file)) {
                    allVideoFiles.add(file);
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {
                System.err.println("Warning: Failed to access file: " + file);
                return FileVisitResult.CONTINUE;
            }
        });

        if (allVideoFiles.isEmpty()) {
            System.out.println("\nNo video files found in input directory");
            return;
        }

        System.out.printf("\nFound %d video files to process%n", allVideoFiles.size());

        // 创建进度计数器
        AtomicInteger processedCount = new AtomicInteger(0);
        long startTime = System.currentTimeMillis();

        // 处理每个视频文件
        for (Path videoPath : allVideoFiles) {
            String inputFilePath = videoPath.toString();
            String relativePath = inputDir.toPath().relativize(videoPath.getParent()).toString();

            // 创建输出目录（保持相同的目录结构）
            File outputDirForFile = new File(outputDir, relativePath);
            if (!outputDirForFile.exists() && !outputDirForFile.mkdirs()) {
                System.err.println("Warning: Failed to create output directory: " + outputDirForFile);
                continue;
            }

            // 生成输出文件名
            String fileName = videoPath.getFileName().toString();
            String baseName = fileName.substring(0, fileName.lastIndexOf('.'));
            String outputPath = new File(outputDirForFile,  baseName + ".mp4").getAbsolutePath();

            System.out.printf("\nProcessing %d/%d: %s%n",
                    processedCount.incrementAndGet(),
                    allVideoFiles.size(),
                    videoPath);

            try {
                convertToNightSurveillance(inputFilePath, outputPath);
                System.out.println("Successfully created: " + outputPath);
            } catch (Exception e) {
                System.err.println("Error processing " + fileName + ": " + e.getMessage());
                e.printStackTrace();
            }
        }

        // 计算总耗时
        long endTime = System.currentTimeMillis();
        double totalSeconds = (endTime - startTime) / 1000.0;
        System.out.printf("\nProcessing completed!%n");
        System.out.printf("Total night surveillance videos created: %d/%d%n", processedCount.get(), allVideoFiles.size());
        System.out.printf("Total time: %.1f seconds%n", totalSeconds);
        System.out.printf("Average time per video: %.1f seconds%n",
                totalSeconds / processedCount.get());
    }

    /**
     * 检查文件是否是视频文件
     */
    private static boolean isVideoFile(Path file) {
        String fileName = file.getFileName().toString().toLowerCase();
        return fileName.matches(".*\\.(mp4|avi|mov|mkv|flv|wmv|mpeg|mpg)$");
    }

    /**
     * 将单个视频文件转换为夜间监控风格
     *
     * @param inputPath 输入视频文件路径
     * @param outputPath 输出视频文件路径
     */
    private static void convertToNightSurveillance(String inputPath, String outputPath) throws Exception {
        long startTime = System.currentTimeMillis();

        // 初始化视频抓取器
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputPath);
        grabber.start();

        // 获取视频信息
        int originalWidth = grabber.getImageWidth();
        int originalHeight = grabber.getImageHeight();
        double originalFrameRate = grabber.getFrameRate();
        long totalFrames = grabber.getLengthInFrames();

        System.out.println("  Original: " + originalWidth + "x" + originalHeight +
                " @ " + String.format("%.1f", originalFrameRate) + "fps");
        System.out.println("  Output will maintain original resolution");
        System.out.println("  Total frames: " + totalFrames);

        // 初始化视频录制器 - 使用原始分辨率
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputPath, originalWidth, originalHeight);
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        recorder.setFormat("mp4");
        recorder.setFrameRate(FRAME_RATE);
        recorder.setVideoBitrate(BITRATE);
        recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
        recorder.setVideoOption("preset", "medium");
        recorder.setVideoOption("crf", "23"); // 较高质量
        recorder.start();

        // 为每个视频生成一个随机夜晚时间戳
        String randomNightTime = generateRandomNightTime();
        System.out.println("  Random night time: " + randomNightTime);

        // 初始化帧计数器
        int frameCount = 0;
        int outputFrameCount = 0;
        int skipRatio = (int) Math.ceil(originalFrameRate / FRAME_RATE);

        // 视频处理主循环
        Frame frame;
        while ((frame = grabber.grabImage()) != null) {
            frameCount++;

            // 跳过帧以匹配目标帧率
            if (frameCount % skipRatio != 0) continue;

            // 应用夜间监控效果（使用相同的随机夜晚时间）
            Frame processedFrame = applyNightEffects(frame, originalWidth, originalHeight, randomNightTime);

            // 录制处理后的帧
            recorder.record(processedFrame);
            outputFrameCount++;

            // 打印进度
            if (outputFrameCount % 50 == 0) {
                double progress = (double) frameCount / totalFrames * 100;
                System.out.printf("  Processed %d/%d frames (%.1f%%)%n",
                        frameCount, totalFrames, progress);
            }
        }

        // 释放资源
        grabber.stop();
        grabber.release();

        recorder.stop();
        recorder.release();

        // 计算处理时间
        long endTime = System.currentTimeMillis();
        double seconds = (endTime - startTime) / 1000.0;
        System.out.printf("  Completed in %.1f seconds (%d output frames)%n",
                seconds, outputFrameCount);
    }

    /**
     * 生成22:00到03:00之间的随机夜晚时间
     *
     * @return 格式为"HH:mm:ss"的时间字符串
     */
    private static String generateRandomNightTime() {
        // 生成22:00到26:59之间的分钟数（26:59表示次日02:59）
        int totalMinutes = 22 * 60 + random.nextInt(5 * 60); // 22:00到02:59

        int hours = totalMinutes / 60;
        int minutes = totalMinutes % 60;
        int seconds = random.nextInt(60); // 随机秒数

        // 如果小时超过24，转换为次日时间
        if (hours >= 24) {
            hours -= 24;
        }

        // 格式化为字符串
        return String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }

    /**
     * 应用夜间监控效果到单个视频帧
     *
     * @param frame 原始视频帧
     * @param originalWidth 原始宽度
     * @param originalHeight 原始高度
     * @param nightTime 随机生成的夜晚时间（格式：HH:mm:ss）
     * @return 处理后的视频帧（保持原始分辨率）
     */
    private static Frame applyNightEffects(Frame frame, int originalWidth, int originalHeight, String nightTime) {
        // 转换为Java2D图像
        Java2DFrameConverter converter = new Java2DFrameConverter();
        java.awt.image.BufferedImage img = converter.convert(frame);

        // 转换为灰度图像（黑白色调）
        java.awt.image.BufferedImage grayImg = new java.awt.image.BufferedImage(
                originalWidth, originalHeight, java.awt.image.BufferedImage.TYPE_BYTE_GRAY);
        java.awt.Graphics g = grayImg.getGraphics();
        g.drawImage(img, 0, 0, originalWidth, originalHeight, null);
        g.dispose();

        // 调整亮度和对比度
        java.awt.image.RescaleOp rescaleOp = new java.awt.image.RescaleOp(
                new float[] { (float) CONTRAST },
                new float[] { (float) (BRIGHTNESS * 255) },
                null);
        java.awt.image.BufferedImage adjustedImg = rescaleOp.filter(grayImg, null);

        // 添加噪点
        addNoise(adjustedImg, NOISE_INTENSITY);

        // 添加模糊效果
        addBlur(adjustedImg, BLUR_SIGMA);

        // 添加监控元素（使用随机夜晚时间）
        addNightSurveillanceElements(adjustedImg, nightTime, originalWidth, originalHeight);

        // 转换回Frame
        return converter.convert(adjustedImg);
    }

    /**
     * 添加噪点到图像
     *
     * @param image 输入图像
     * @param intensity 噪点强度 (0.0-1.0)
     */
    private static void addNoise(java.awt.image.BufferedImage image, double intensity) {
        java.util.Random rand = new java.util.Random();
        int width = image.getWidth();
        int height = image.getHeight();

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                if (rand.nextDouble() < intensity) {
                    int rgb = image.getRGB(x, y);
                    int gray = (rgb >> 16) & 0xFF; // 灰度图像的R、G、B值相同
                    int noise = rand.nextInt(60) - 30; // -30到30的随机噪点
                    int newGray = Math.max(0, Math.min(255, gray + noise));
                    int newRGB = (newGray << 16) | (newGray << 8) | newGray;
                    image.setRGB(x, y, newRGB);
                }
            }
        }
    }

    /**
     * 添加高斯模糊效果
     *
     * @param image 输入图像
     * @param sigma 模糊程度
     */
    private static void addBlur(java.awt.image.BufferedImage image, double sigma) {
        int size = (int)(sigma * 3) * 2 + 1; // 确保为奇数
        if (size < 3) size = 3;

        // 创建高斯模糊核
        float[] kernel = createGaussianKernel(size, sigma);
        java.awt.image.Kernel awtKernel = new java.awt.image.Kernel(size, size, kernel);
        java.awt.image.ConvolveOp convolve = new java.awt.image.ConvolveOp(
                awtKernel, java.awt.image.ConvolveOp.EDGE_NO_OP, null);

        java.awt.image.BufferedImage blurred = convolve.filter(image, null);

        // 将模糊后的图像复制回原图
        java.awt.Graphics2D g2d = image.createGraphics();
        g2d.drawImage(blurred, 0, 0, null);
        g2d.dispose();
    }

    /**
     * 创建高斯模糊核
     *
     * @param size 核大小
     * @param sigma 标准差
     * @return 高斯核数组
     */
    private static float[] createGaussianKernel(int size, double sigma) {
        float[] kernel = new float[size * size];
        double twoSigmaSquared = 2 * sigma * sigma;
        double sum = 0.0;

        int center = size / 2;
        for (int y = 0; y < size; y++) {
            for (int x = 0; x < size; x++) {
                int dx = x - center;
                int dy = y - center;
                double distanceSquared = dx * dx + dy * dy;
                double value = Math.exp(-distanceSquared / twoSigmaSquared);
                kernel[y * size + x] = (float)value;
                sum += value;
            }
        }

        // 归一化
        for (int i = 0; i < kernel.length; i++) {
            kernel[i] /= sum;
        }

        return kernel;
    }

    /**
     * 添加监控元素（随机夜晚时间戳和REC指示器）
     *
     * @param image 输入图像
     * @param nightTime 随机生成的夜晚时间（格式：HH:mm:ss）
     * @param width 图像宽度
     * @param height 图像高度
     */
    private static void addNightSurveillanceElements(java.awt.image.BufferedImage image, String nightTime, int width, int height) {
        java.awt.Graphics2D g2d = image.createGraphics();

        // 设置抗锯齿关闭（模拟低分辨率监控）
        g2d.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING,
                java.awt.RenderingHints.VALUE_ANTIALIAS_OFF);
        g2d.setRenderingHint(java.awt.RenderingHints.KEY_TEXT_ANTIALIASING,
                java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);

        // 设置字体大小（根据图像高度动态调整）
        int fontSize = Math.max(12, Math.min(24, height / 30));
        java.awt.Font font = new java.awt.Font("Courier New", java.awt.Font.BOLD, fontSize);
        g2d.setFont(font);

        // 添加REC指示器（左上角）- 固定位置
        g2d.setColor(java.awt.Color.RED);
        int recIndicatorSize = Math.max(8, Math.min(16, height / 45));
        g2d.fillOval(15, 15, recIndicatorSize, recIndicatorSize); // 红色圆点
        g2d.setColor(java.awt.Color.WHITE);
        g2d.drawString("REC", 15 + recIndicatorSize + 5, 15 + recIndicatorSize / 2 + 4); // REC文字

        // 添加时间戳（右下角）- 使用随机夜晚时间
        // 获取当前日期（年月日）+ 随机夜晚时间
        String currentDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String timestamp = currentDate + " " + nightTime;

        java.awt.FontMetrics fm = g2d.getFontMetrics();
        int textWidth = fm.stringWidth(timestamp);
        int textHeight = fm.getHeight();

        // 绘制半透明背景
        g2d.setColor(new java.awt.Color(0, 0, 0, 180)); // 半透明黑色
        g2d.fillRect(width - textWidth - 20,
                height - textHeight - 15,
                textWidth + 15,
                textHeight + 5);

        // 绘制时间戳文字（白色）
        g2d.setColor(java.awt.Color.WHITE);
        g2d.drawString(timestamp,
                width - textWidth - 15,
                height - 20);

        // 添加摄像头标识（右上角）
        String cameraId = "CAM-01 [NIGHT]";
        int camTextWidth = fm.stringWidth(cameraId);
        g2d.setColor(java.awt.Color.GREEN);
        g2d.drawString(cameraId, width - camTextWidth - 20, 20 + fontSize);

        g2d.dispose();
    }
}